
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// use libesmtp
#include <ctype.h>
#include <fcntl.h>
#include <openssl/ssl.h>
#include <auth-client.h>
#include <libesmtp.h>
static int authinteract (auth_client_request_t request, char **result,
    int fields, void *arg)
{
  printf("%s\n", __func__);
  int i;
  char **userpwd = (char **)arg;
  printf("user:%s pwd:%s\n", userpwd[0], userpwd[1]);

  for (i = 0; i < fields; i++) {
    if (request[i].flags & AUTH_PASS) {
      result[i] = userpwd[1];
    } else {
      result[i] = userpwd[0];
    }
  }
  return 1;
}
    //const char *hostport,
void *email_send(const char *mailbox, const char *authorizationCode,
    const char *recv, const char *msg)
{
  smtp_session_t session;
  smtp_message_t message;
  const smtp_status_t *status;
  auth_context_t authctx;
  smtp_recipient_t recipient;
  const char *userpwd[2], *hostport = NULL;
  userpwd[0] = mailbox;
  userpwd[1] = authorizationCode;

  int len = strlen(mailbox);
  char *qq_email_suffix = "@qq.com";
  if (strcmp(mailbox+len-strlen(qq_email_suffix), qq_email_suffix) == 0) {
    hostport = "smtp.qq.com";
  } else {
    printf("[ERROR] INVALID EMAIL:%s\n", mailbox);
    exit(1);
  }
  printf("[DEBUG] hostport:%s\n", hostport);

  auth_client_init ();
  authctx = auth_create_context ();
  session = smtp_create_session();
  message = smtp_add_message(session);

  auth_set_mechanism_flags (authctx, AUTH_PLUGIN_PLAIN, 0);
  auth_set_interact_cb (authctx, authinteract, userpwd);
  smtp_auth_set_context (session, authctx);
  auth_client_enabled(authctx);


  smtp_starttls_enable (session, Starttls_REQUIRED);
  smtp_set_server(session, hostport);
  smtp_set_reverse_path(message, mailbox);
  recipient = smtp_add_recipient(message, recv);
  smtp_dsn_set_notify (recipient, Notify_NOTSET);
  smtp_set_header (message, "To", NULL, NULL);
  smtp_set_header(message, "Subject", msg);
  smtp_set_header_option (message, "Subject", Hdr_OVERRIDE, 1);
  smtp_set_message_str(message, (void *)msg);
  if (!smtp_start_session (session)) {
    char buf[128];
    fprintf (stderr, "SMTP server problem %s\n",
        smtp_strerror (smtp_errno (), buf, sizeof buf));
  } else {
    status = smtp_message_transfer_status (message);
    printf ("%d %s", status->code,
        (status->text != NULL) ? status->text : "\n");
  }
  smtp_destroy_session (session);
  auth_destroy_context (authctx);
  auth_client_exit ();
  return NULL;
}
// end libesmtp
#ifdef USE_GLIB
#include <gio/gio.h>
#include <glib.h>

void *email_read(int fd)
{
  char buffer[1024] = {0};
  size_t size;

  do {
    size = g_input_stream_read (istream, buffer, sizeof buffer, NULL, &error);
    if (size < 0) {
      g_printerr ("Error receiving from socket: %s\n", error->message);
      goto out;
    }
  } while (size < 1);
  g_print ("L%d f-%s++++%d:%.*s\n", __LINE__, __func__, (int)size, (int)size, buffer);
out:
  return strdup (buffer);
}
int email_write (void *ostream, const char *buf, int flag)
{
  gsize size;
  GError *error;
  char *buffer = NULL;

  if (flag) {
    buffer = g_base64_encode((guchar *)buf, strlen(buf));
    size = g_output_stream_write (ostream, buffer, strlen(buffer), NULL, &error);
  } else {
    size = g_output_stream_write (ostream, buf, strlen(buf), NULL, &error);
  }
  if (size < 1) {
	  g_printerr ("Error receiving from socket: %s\n",
		      error->message);
    goto out;
	}
out:
  if (buffer) {
    g_print ("L%d f-%s----%d:%.*s\n", __LINE__, __func__,(int)size, (int)size,
        buffer);
    g_free(buffer);
  } else {
    g_print ("L%d f-%s----%d:%.*s\n", __LINE__, __func__, (int)size, (int)size, buf);
  }
  size = g_output_stream_write (ostream, "\r\n", 2, NULL, &error);
  return size;
}
static gboolean make_connection (const char       *argument,
		 GTlsCertificate  *certificate,
		 GCancellable     *cancellable,
		 GSocket         **socket,
		 GSocketAddress  **address,
		 GIOStream       **connection,
		 GInputStream    **istream,
		 GOutputStream   **ostream,
		 GError          **error)
{
  GSocketAddressEnumerator *enumerator;
  GSocketConnectable *connectable;
  GSocketAddress *src_address;
//  GTlsInteraction *interaction;
  GError *err = NULL;
  int read_timeout = 100;

  *socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, 0, error);
  g_socket_set_timeout (*socket, read_timeout);
  connectable = g_network_address_parse (argument, 7777, error);
  if (connectable == NULL)
    return FALSE;

  enumerator = g_socket_connectable_enumerate (connectable);
  while (TRUE)
    {
      *address = g_socket_address_enumerator_next (enumerator, cancellable, error);
      if (*address == NULL)
        {
          if (error != NULL && *error == NULL)
            g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                                 "No more addresses to try");
          return FALSE;
        }

      if (g_socket_connect (*socket, *address, cancellable, &err))
        break;
      //g_message ("Connection to %s failed: %s, trying next", socket_address_to_string (*address), err->message);
      g_clear_error (&err);

      g_object_unref (*address);
    }
  g_object_unref (enumerator);
//  g_print ("Connected to %s\n", socket_address_to_string (*address));

  src_address = g_socket_get_local_address (*socket, error);
  if (!src_address)
    {
      g_prefix_error (error, "Error getting local address: ");
      return 0;
    }

  //g_print ("local address: %s\n",
    //       socket_address_to_string (src_address));
  g_object_unref (src_address);
  *connection = G_IO_STREAM (g_socket_connection_factory_create_connection (*socket));
  g_object_unref (connectable);

  if (*connection)
    {
      *istream = g_io_stream_get_input_stream (*connection);
      *ostream = g_io_stream_get_output_stream (*connection);
    }
  return 1;
}
void email_qq_verification (const char *argument,
    const char *from, const char *pwd, const char *to, const char *data)
{
  GSocket *socket = NULL;
  GSocketAddress *address = NULL;
  GError *error = NULL;
 // GOptionContext *context = NULL;
  GCancellable *cancellable = NULL;
  GIOStream *connection = NULL;
  GInputStream *istream = NULL;
  GOutputStream *ostream = NULL;
  //GSocketAddress *src_address = NULL;
  GTlsCertificate *certificate = NULL;
 // gsize base_len;
  char buf[1024] = {0}, *msg = NULL;//*base, ;
 // gint i;

  address = NULL;
  connection = NULL;
  if (!make_connection ("157.148.54.34:25",
        //argument,
        certificate, cancellable, &socket, &address,
                       &connection, &istream, &ostream, &error))
  {
    g_error ("make connect \n");
    goto out;
  }
  msg = email_read(istream);
  email_write(ostream, "auth login", 0);
  msg = email_read(istream);
  g_print ("L%d f-%s++++%ld:%s\n", __LINE__, __func__, strlen(msg), msg);
  email_write(ostream, from, 1);
  msg = email_read(istream);
  email_write(ostream, pwd, 1);
  msg = email_read(istream);
  email_write(ostream, "HELO DEBIAN", 0);
  msg = email_read(istream);
  g_snprintf(buf, sizeof buf, "mail from:<%s>", from);
  email_write(ostream, buf, 0);
  msg = email_read(istream);
  g_snprintf(buf, sizeof buf, "rcpt to:<%s>", to);
  email_write(ostream, buf, 0);
  msg = email_read(istream);
  email_write(ostream, "data", 0);
  msg = email_read(istream);
  g_snprintf(buf, sizeof buf,
      "subject:hello email\r\nfrom:8300社区<%s>\r\nto:me\r\n\r\n%s\r\n.\r\n",
      from, data);
  email_write(ostream, buf, 0);
  email_write(ostream, "quit", 0);

  if (!g_io_stream_close (connection, cancellable, &error)) {
	  g_printerr ("Error closing connection: %s\n",
		      error->message);
	  goto out;
	}
  g_object_unref (connection);
  g_print ("closing socket\n");
out:
  g_object_unref (socket);
  g_object_unref (address);

  return;
}
#endif
